/*
 * Copyright (c)  2018, XiQiao
 * All rights reserved. 
 *
 * Id:ExcelTool.java   2018-07-26 21:03 wanglijun
 */
package io.marmot.poi;

import io.marmot.poi.domain.ExcelMapping;
import io.marmot.poi.exception.ExcelException;
import io.marmot.poi.factory.ExcelMappingFactory;
import io.marmot.poi.handler.ExcelReaderHandler;
import io.marmot.poi.reader.ExcelReader;
import io.marmot.poi.util.Const;
import io.marmot.poi.util.ExcelUtil;
import io.marmot.poi.writer.ExcelWriter;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

/**
 * <p>
 * Title:
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2018
 * </p>
 * <p>
 * Company: XiQiao
 * </p>
 *
 * @author: wanglijun
 * @create: 2018-07-26 21:03
 * @version：1.0
 */
public class ExcelTool {
    /**泛型*/
    private Class<?> clazz = null;
    /**HTTP响应*/
    private HttpServletResponse mResponse = null;

    private OutputStream outputStream = null;
    /***
     * 最大记录数据
     */
    private Integer maxSheetRecords = 50000;

    private String currentOptionMode = MODE_EXPORT;

    private final static String MODE_EXPORT = "$MODE_EXPORT$";

    private final static String MODE_BUILD = "$MODE_BUILD$";

    private final static String MODE_IMPORT = "$MODE_IMPORT$";

    protected  ExcelTool(){

    }



    public static ExcelTool importExcel(Class<?> clazz){
        return new ExcelTool(clazz);
    }

    /***
     * 导出文件为下载文件
     * @param clazz
     * @param response
     * @return
     */
    public ExcelTool export(Class<?> clazz,HttpServletResponse response){
        return new ExcelTool (clazz,response);
    }


    /***
     * 导出为OutPutStream
     * @param clazz
     * @param outputStream
     * @return
     */
    public static ExcelTool builder(Class<?> clazz, OutputStream outputStream) {
        return new ExcelTool(clazz, outputStream);
    }

    public void writer(List<?> data, boolean isTemplate) {
        if (!currentOptionMode.equals(MODE_BUILD)) {
            throw new ExcelException("请使用com.wuwenze.poi.ExcelKit.$Builder(Class<?> clazz, OutputStream outputStream)构造器初始化参数.");
        }
        ExcelMapping excelMapping = ExcelMappingFactory.get(clazz);
        ExcelWriter excelWriter = new ExcelWriter(excelMapping, maxSheetRecords);
        SXSSFWorkbook workbook = excelWriter.generateWorkbook(data, isTemplate);
        ExcelUtil.write(workbook, this.outputStream);
    }

    public  void reader(File file, ExcelReaderHandler<?> handler){
        try {
            InputStream inputStream = new FileInputStream (file);
            this.reader(inputStream, -1,null,handler);
        } catch (FileNotFoundException e) {
            throw new ExcelException(e);
        }
    }

    public  void readerForSheetName(File file,String sheetName, ExcelReaderHandler<?> handler){
        try {
            InputStream inputStream = new FileInputStream (file);
            this.reader(inputStream, -1,sheetName,handler);
        } catch (FileNotFoundException e) {
            throw new ExcelException(e);
        }
    }

    public  void readerForSheetIndex(File file,Integer sheetIndex,ExcelReaderHandler<?> handler){
        try {
            InputStream inputStream = new FileInputStream (file);
            this.reader(inputStream, sheetIndex,null,handler);
        } catch (FileNotFoundException e) {
            throw new ExcelException(e);
        }
    }
    /***
     *
     * @param inputStream
     * @param sheetIndex
     * @param sheetName
     * @param handler
     */
    public  void reader(InputStream inputStream, Integer sheetIndex, String sheetName, ExcelReaderHandler<?> handler){
        if(!this.currentOptionMode.equals (MODE_IMPORT)){
            throw new ExcelException ("请使用io.marmot.poi.ExcelTool.Import(Class<?> clazz)构造器初始化参数.");
        }
        ExcelMapping excelMapping=ExcelMappingFactory.get (this.clazz);
        ExcelReader excelReader=new ExcelReader(this.clazz,excelMapping,handler);
        if(sheetIndex>=0){
            excelReader.process (inputStream,sheetIndex);
            return;
        }
//        if(StringUtils.isNotEmpty (sheetName)){
//            excelReader.processForSheetName(inputStream,sheetName);
//            return;
//        }
        excelReader.process(inputStream);
        return;
    }

    /**
     * 下载Excel文件
     * @param data
     * @param template
     */
    public void download(List<?> data,Boolean template){
        if(this.currentOptionMode.equals (MODE_EXPORT)){
            throw new ExcelException (" 请使用export(Class<?> clazz,HttpServletResponse response)构造初始化参数");
        }
        try {
        ExcelMapping excelMapping= ExcelMappingFactory.get(this.clazz);

        ExcelWriter excelWriter = new ExcelWriter (excelMapping, maxSheetRecords);

        SXSSFWorkbook workbook=excelWriter.generateWorkbook(data,template);

        String fileName =this.getFileName (template,excelMapping.getName ());

            ExcelUtil.download(workbook, mResponse, URLEncoder.encode(fileName, Const.ENCODING));
        } catch (Exception e) {
              throw new ExcelException (e);
        }

    }


    private String getFileName(Boolean template,String sheetName){
        return template ? (sheetName+ "-导入模板.xlsx") : (sheetName + "-导出结果.xlsx");
    }

    /***
     *
     * @param clazz
     */
    protected ExcelTool(Class<?> clazz) {
        this(clazz, null, null);
        this.currentOptionMode = MODE_IMPORT;
    }

    protected ExcelTool(Class<?> clazz, OutputStream outputStream) {
        this(clazz, outputStream, null);
        this.currentOptionMode = MODE_BUILD;
    }

    protected ExcelTool(Class<?> clazz, HttpServletResponse response) {
        this(clazz, null, response);
        this.currentOptionMode = MODE_EXPORT;
    }

    protected ExcelTool(Class<?> clazz, OutputStream outputStream, HttpServletResponse response) {
        this.clazz = clazz;
        this.outputStream = outputStream;
        this.mResponse = response;
    }


    /**
     * 计算两个单元格之间的单元格数目(同一行)
     *
     * @return int
     */
    public static int countNullCell(String ref, String ref2) {
        // excel2007最大行数是1048576，最大列数是16384，最后一列列名是XFD
        String xfd = ref.replaceAll("\\d+", "");
        String xfd_1 = ref2.replaceAll("\\d+", "");

        xfd = fillChar(xfd, 3, '@', true);
        xfd_1 = fillChar(xfd_1, 3, '@', true);

        char[] letter = xfd.toCharArray();
        char[] letter_1 = xfd_1.toCharArray();
        int res = (letter[0] - letter_1[0]) * 26 * 26 + (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]);
        return res - 1;
    }

    private static String fillChar(String str, int len, char let, boolean isPre) {
        int len_1 = str.length();
        if (len_1 < len) {
            if (isPre) {
                for (int i = 0; i < (len - len_1); i++) {
                    str = let + str;
                }
            } else {
                for (int i = 0; i < (len - len_1); i++) {
                    str = str + let;
                }
            }
        }
        return str;
    }

}
